#ifndef PFS_INODE_H
#define PFS_INODE_H
#include <string>
#include <sys/types.h>
#include <map>
#include <set>
#include "../utils/Lock.h"
#include <time.h>
#include "block_map.h"
#include <stdint.h>
#include <ext/hash_map>
using namespace std;
namespace PFS
{
    class DirCount
    {
        public:
            DirCount()
            {
                namespace_count = 0;
                diskspace_count = 0;
            }
            DirCount(long ns, long ds)
                :namespace_count(ns), diskspace_count(ds)
            {}
            long get_namespace_count()
            { return namespace_cout;}
            void set_namespace_count(long ns)
            { namespace_count = ns;}
            long get_diskspace_count()
            { return diskspace_count; }
            void set_diskspace_count(long ds)
            { diskspace_count = ds; }
        private:
            long namespace_count;
            long diskspace_count;
    };
    class UniqueID
    {
        public:
            UniqueID() : id(0),seed(0)
             {}
            UniqueID(u_int64_t id, u_int64_t seed)
            {
                this->id = id;
                this->seed = seed;
            }
            u_int64_t gen_id(){ return ++seed; }
            u_int64_t get_seed(){ return seed; }
            void set_seed(u_int64_t s) { seed = s;}
            u_int64_t get_id() const {return id;}
        private:
            u_int64_t id;
            u_int64_t seed;
    };
    class INodeDict;
    class INode
    {//for INodeDict ,just store itself name, foe INdoeFile, store total name,allow file use the same name where threr are in different dict
        public:
            INode();
            INode(const string&);
            INode(const INode & ln);
            virtual ~INode();
            void set_access_time(time_t timer);
            long get_access_time();
            void set_modify_time(time_t timer);
            long get_modify_time();
            string get_name();
            const char* get_name() const;
            void set_name(const char* name);
            bool is_root(){return name.empty();}
            virtual bool is_directory() = 0;
            INodeDict* get_parent();
            void set_parent(INodeDict*);
            long get_namespace_quota();
            long get_diskspace_quota();
            bool remove_node(bool force_del = false);
            inline virtual void rename(const char* new_name)
            {
                name = string(new_name);
            }
        protected:
            string name;
            INodeDict* parent;
            time_t access_time;
            time_t modify_time;
            time_t create_time;
            RWLock lock; //read write lock
        private:
            long permission;
    };

    class INodeDict : public INode
    {
        public:
            INodeDict();
            INodeDict(const string& name);
            INodeDict(const INodeDict &ln);
            virtual ~INodeDict();

            virtual bool is_directory();
            bool remove_child(const strig& name,bool force_del = false);
            INode* replace_child(const string& name, INode* new_node);
            bool exsit_child(const string& name);
            INode* get_child(const string& name);
            void add_child(INode* node);
            virtual void rename(const char* new_name)
            {
                INode::rename(new_name);
            }
        private:
            hash_map<const char*,INode*,__gnu_cxx::hash<const char*>, equal_str > children;
    };

    class INodeFile : public INode
    {
        public:
            INodeFile();
            INodeFile(const string&);
            virtual ~INodeFile();
            virtual bool is_directory() {return false;}
            void add_block(BlockLocate *block);//when block->block_info->file_name = this.name ,then add
            bool remove_block(const uint32_t);
            BlockLocate* replace_block(const uint32_t block_id, BlockLocate *new_block);
            bool exsit_block(const uint32_t block_id);
            BlockLocate* get_block(const uint32_t block_id);
            uint64_t get_file_size() const;
            virtual void rename(const char* new_name)
            {
                INode::rename(new_name);
                BLOCK_MAP bl = blocks->get_block_map();
                BLOCK_MAP_ITER it;
                for( it = bl.begin(); it != bl.end(); it++)
                    it->second = string(new_name);
            }
            BlockLocate* create_block(const uint32_t block_id)
            {
                return blocks->create(block_id, false);
            }
//            void set_permission(long permission);
//            long get_permission();
        private:
            BlockMap *blocks;
            map<int32_t, uint32_t> content_block; //sort by block_info.index_of_file;
            uint64_t file_size;
    };
}
#endif
